/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hannesdorfmann.mosby3.mvp.lce;

import com.hannesdorfmann.mosby3.mvp.widget.CirleProgressImg;
import com.hannesdorfmann.mosby3.mvp.MvpAbilitySlice;
import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.Text;
import ohos.agp.window.dialog.ToastDialog;

/**
 * A {@link MvpLceAbilitySlice} that implements {@link MvpLceView} which gives you 3 options:
 * <ul>
 * <li>Display a loading view: A view with <b>ResourceTable.Id_loadingView</b> must be specified in your
 * inflated xml layout</li>
 * <li>Display a error view: A <b>TextView</b> with <b>ResourceTable.Id_errorView</b> must be declared in your
 * inflated xml layout</li>
 * <li>Display content view: A view with <b>ResourceTable.Id_contentView</b> must be specified in your
 * inflated
 * xml layout</li>
 * </ul>
 *
 * @param <CV> The type of the content view with the id = ResourceTable.Id_contentView. Can be any kind of
 *             HarmonyOS component widget like ListContainer, ScrollView or a simple layout like Stacklayout
 *             etc. (everything that extends from ohos.agp.components.Component)
 * @param <M>  The underlying data model that will be displayed with this view
 * @param <V>  The View interface that must be implemented by this view. You can use {@link
 *             MvpLceView}, but if you want to add more methods you have to provide your own view interface
 *             that
 *             extends from {@link MvpLceView}
 * @param <P>  The type of the Presenter. Must extend from {@link MvpPresenter}
 */
public abstract class MvpLceAbilitySlice<CV extends Component, M, V extends MvpLceView<M>, P extends MvpPresenter<V>>
        extends MvpAbilitySlice<V, P> implements MvpLceView<M> {

    protected CirleProgressImg loadingView;
    protected CV contentView;
    protected Text errorView;
    protected Component view;
    protected ComponentContainer mComponentContainer;
    protected int loadingViewID,contentViewID,errorViewID;

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        mComponentContainer = getUIContent();
        setUIContent(mComponentContainer);
        initLceComponetID();
        initCompoment();
    }


    protected abstract ComponentContainer getUIContent();
    protected abstract void initLceComponetID();
    protected void initCompoment() {
        loadingView = createLoadingView();
        contentView = createContentView();
        errorView = createErrorView();

        if (loadingView == null) {
            throw new NullPointerException(
                    "Loading view is null! Have you specified a loading view in your layout xml file?"
                            + " You have to give your loading View the id ResourceTable.Id_loadingView");
        }

        if (contentView == null) {
            throw new NullPointerException(
                    "Content view is null! Have you specified a content view in your layout xml file?"
                            + " You have to give your content View the id ResourceTable.Id_contentView");
        }

        if (errorView == null) {
            throw new NullPointerException(
                    "Error view is null! Have you specified a content view in your layout xml file?"
                            + " You have to give your error View the id ResourceTable.Id_errorView");
        }

        errorView.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component v) {
                onErrorViewClicked();
            }
        });
    }


    /**
     * Create the loading view. Default is {@code findComponentById(ResourceTable.Id_loadingView)}
     *
     * @return the loading view
     */
    protected CirleProgressImg createLoadingView() {
        return (CirleProgressImg) mComponentContainer.findComponentById(loadingViewID/*ResourceTable.Id_loadingView*/);
    }

    /**
     * Create the content view. Default is {@code findComponentById(ResourceTable.Id_contentView)}
     *
     * @return the content view
     */
    protected CV createContentView() {
        return (CV) mComponentContainer.findComponentById(contentViewID/*ResourceTable.Id_contentView*/);
    }

    /**
     * Create the error view. Default is {@code findComponentById(ResourceTable.Id_errorView)}
     *
     * @return the error view
     */
    protected Text createErrorView() {
        return (Text) mComponentContainer.findComponentById(errorViewID/*ResourceTable.Id_errorView*/);
    }

    @Override
    public void showLoading(boolean pullToRefresh) {
        if (!pullToRefresh) {
            animateLoadingViewIn();
        }

        // otherwise the pull to refresh widget will already display a loading animation
    }

    /**
     * Override this method if you want to provide your own animation for showing the loading view
     */
    protected void animateLoadingViewIn() {
        LceAnimator.showLoading(loadingView, contentView, errorView);
    }

    @Override
    public void showContent() {
        animateContentViewIn();
    }

    /**
     * Called to animate from loading view to content view
     */
    protected void animateContentViewIn() {
        LceAnimator.showContent(loadingView, contentView, errorView);
    }

    /**
     * Get the error message for a certain Exception that will be shown on {@link
     * #showError(Throwable, boolean)}
     */
    protected abstract String getErrorMessage(Throwable e, boolean pullToRefresh);

    /**
     * The default behaviour is to display a toast message as light error (i.e. pull-to-refresh
     * error).
     * Override this method if you want to display the light error in another way (like crouton).
     */
    protected void showLightError(String msg) {
        if (getAbility() != null) {
            ToastDialog mToastDialog = new ToastDialog(getContext());
            mToastDialog.setText(msg);
            mToastDialog.setDuration(1000);
            mToastDialog.show();
        }
    }

    /**
     * Called if the error view has been clicked. To disable clicking on the errorView use
     * <code>errorView.setClickable(false)</code>
     */
    protected void onErrorViewClicked() {
        loadData(false);
    }

    @Override
    public void showError(Throwable e, boolean pullToRefresh) {
        String errorMsg = getErrorMessage(e, pullToRefresh);

        if (pullToRefresh) {
            showLightError(errorMsg);
        } else {
            errorView.setText(errorMsg);
            animateErrorViewIn();
        }
    }

    /**
     * Animates the error view in (instead of displaying content view / loading view)
     */
    protected void animateErrorViewIn() {
        LceAnimator.showErrorView(loadingView, contentView, errorView);
    }

    @Override
    public void onStop() {
        super.onStop();
        loadingView = null;
        contentView = null;
        errorView.setClickedListener(null);
        errorView = null;
    }
}

